#include <iostream>
#include <cstring>
#include <unistd.h>
#include <pthread.h>
#include <sys/syscall.h>

using namespace std;

//__thread int global_value = 100;
// int global_value = 100; // 临界资源

// void *startRoutine(void *args)
// {
//     cout << "线程分离..." << endl;
//     while(true)
//     {
//         // 临界区
//         cout << "thread " << pthread_self() <<  " global_value: " 
//             << global_value << " &global_value: " << &global_value 
//             << " Inc: " << global_value++ << " lwp: " << syscall(SYS_gettid) << endl;
//         sleep(1);
//     }
// }

// int 票数计数器
int tickets = 10000; // 临界资源，可能会因为共同访问，造成数据不一致问题
pthread_mutex_t mutex;

void *getTickets(void *args)
{
    const char *name = static_cast<const char*>(args);
    while(true)
    {
        // 临界区，只需要对临界区加锁，而且加锁的粒度越细越好
        // 加锁的本质式让线程执行临界区代码串行化
        // 加锁是一套规范，通过临界区对临界资源进行访问的时候，要加锁就都要加
        // 锁保护的是临界区，任何线程执行临界区代码访问临界资源，都必须先申请锁，前提是都必须先看到锁
        // 那么这把锁，本身不就是也是临界资源吗？那谁来保护这把锁呢？
        // pthread_mutex_lock: 竞争和申请锁的过程，就是原子的，不会被影响。
        // 难道在加锁的临界区里面，就没有线程切换了吗？
        pthread_mutex_lock(&mutex);
        if(tickets > 0)
        {
            usleep(1000);
            cout << name << " 抢到了票，票的编号: " << tickets << endl;
            tickets--;
            pthread_mutex_unlock(&mutex);

            // other code
            usleep(100); // 模拟其它业务逻辑的执行
        }
        else
        {
            cout << name << "] 已经放弃抢票了，因为没有了..." << endl;
            pthread_mutex_unlock(&mutex);
            break;
        }
    }
    

    return nullptr;
}

int main()
{
    pthread_mutex_init(&mutex, nullptr);
    pthread_t tid1;
    pthread_t tid2;
    pthread_t tid3;
    pthread_t tid4;
    pthread_create(&tid1, nullptr, getTickets, (void*) "thread 1");
    pthread_create(&tid2, nullptr, getTickets, (void*) "thread 2");
    pthread_create(&tid3, nullptr, getTickets, (void*) "thread 3");
    pthread_create(&tid4, nullptr, getTickets, (void*) "thread 4");

    //sleep(1);

    // pthread_detach(tid1);
    // pthread_detach(tid2);
    // pthread_detach(tid3);

    int n = pthread_join(tid1, nullptr);
    cout << n << ":" << strerror(n) << endl;
    n = pthread_join(tid2, nullptr);
    cout << n << ":" << strerror(n) << endl;
    n = pthread_join(tid3, nullptr);
    cout << n << ":" << strerror(n) << endl;
    n = pthread_join(tid4, nullptr);
    cout << n << ":" << strerror(n) << endl;

    // 释放锁
    pthread_mutex_destroy(&mutex);

    return 0;
}